package com.gpj.netty.application.server;

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

/**
 * @className NIOSimpleServer
 * @description 简单NIO服务端代码
 *  * simple -- 最简单的NIO通信服务端代码
 *  * senior -- 进阶版的NIO通信服务端代码
 * @author GPJ
 * @date 2021/11/30 17:28
 * @version 1.0
 **/
@Slf4j
public class NIOSimpleServer {
	public static void main(String[] args) throws IOException {
//		NetWorkServer.simple();
		NIOSimpleServer.senior();
	}

	public static void simple()  throws IOException {
		// 创建一个在本地端口进行监听的服务Socket通道.并设置为非阻塞方式
		ServerSocketChannel serverSocket = ServerSocketChannel.open();
		// 必须配置为非阻塞才能往selector上注册，否则会报错，selector模式本身就是非阻塞模式
		serverSocket.configureBlocking(false);
		// 绑定端口
		serverSocket.socket().bind(new InetSocketAddress(9000));
		log.debug("服务端启动完成");

		while (true){
			log.debug("等待连接...");
			// 非阻塞模式accept方法不会阻塞，否则会阻塞
			// NIO的非阻塞是由操作系统内部实现的，底层调用了linux内核的accept函数
			SocketChannel socket = serverSocket.accept();

			if(socket == null) {
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				continue;
			}

			log.debug("接收到新的客户端连接");

			handle(socket);
		}
	}

	public static void senior()  throws IOException {
		// 创建一个在本地端口进行监听的服务Socket通道.并设置为非阻塞方式
		ServerSocketChannel serverSocket = ServerSocketChannel.open();
		// 必须配置为非阻塞才能往selector上注册，否则会报错，selector模式本身就是非阻塞模式
		serverSocket.configureBlocking(false);
		// 绑定端口
		serverSocket.socket().bind(new InetSocketAddress(9000));
		log.debug("服务端启动完成");

		while (true){
			log.debug("等待连接...");
			// 非阻塞模式accept方法不会阻塞，否则会阻塞
			// NIO的非阻塞是由操作系统内部实现的，底层调用了linux内核的accept函数
			SocketChannel socket = serverSocket.accept();

			if(socket == null) {
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				continue;
			}

			log.debug("接收到新的客户端连接");

			new Thread(() -> {
				handle(socket);
			}).start();
		}
	}

	private static void handle(SocketChannel socketChannnel){
		try {
			log.debug("准备读取数据...");
			ByteBuffer buffer = ByteBuffer.allocate(1024);
			socketChannnel.read(buffer);
			log.debug("客户端数据读取完毕");

			String request = new String(buffer.array(), 0, buffer.position());
			log.info("接收到客户端的数据：{}", request);

			log.debug("准备响应请求...");
			ByteBuffer writeBuffer = ByteBuffer.wrap(("服务端接收到请求:{" + request + "}").getBytes());
			socketChannnel.write(writeBuffer);
			log.debug("响应请求完毕");
		} catch (Exception e){
			log.error("数据处理异常：{}", e.toString(), e);
		}
	}
}
